Here I experiment with combining flow fields with images (dithering).
Load packages:
library(ggnewscale)
library(imager)
Loading required package: magrittr
Attaching package: ‘imager’
The following object is masked from ‘package:magrittr’:
add
The following objects are masked from ‘package:stats’:
convolve, spectrum
The following object is masked from ‘package:graphics’:
frame
The following object is masked from ‘package:base’:
save.image
library(sf)
Linking to GEOS 3.9.1, GDAL 3.2.1, PROJ 7.2.1; sf_use_s2() is TRUE
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
-- Attaching packages ------------------------------------------------------------------ tidyverse 1.3.1 --
v ggplot2 3.3.5 v purrr 0.3.4
v tibble 3.1.6 v dplyr 1.0.7
v tidyr 1.1.4 v stringr 1.4.0
v readr 2.1.1 v forcats 0.5.1
-- Conflicts --------------------------------------------------------------------- tidyverse_conflicts() --
x imager::add() masks magrittr::add()
x stringr::boundary() masks imager::boundary()
x tidyr::extract() masks magrittr::extract()
x tidyr::fill() masks imager::fill()
x dplyr::filter() masks stats::filter()
x dplyr::lag() masks stats::lag()
x purrr::set_names() masks magrittr::set_names()
Process image - snowscape
Read the image using imager::load.image():
#melville <- image_read("melville_lg.jpg")
snowscape <- load.image("snowscape.jpg")
Check the size of the image:
summary(snowscape)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.0000 0.1686 0.4118 0.4195 0.5843 1.0000
Convert image to data frame (still working with {imager}):
snowscape_df <- snowscape %>%
as.data.frame(wide="c") %>%
mutate(color = rgb(c.1,
c.2,
c.3))
Convert to grayscale and to data frame:
snowscape_df_grayscale <- snowscape %>%
grayscale() %>%
as.data.frame()
Join data frames with color and grayscale values:
snowscape_df <- snowscape_df %>%
left_join(snowscape_df_grayscale,
by = c("x", "y"))
Retrieve every nth row/column from image:
nx <- 10
ny <- 20
snowscape_sampled <- snowscape_df %>%
filter(x %% nx == 1,
y %% ny == 1)
Plot:
snowscape_sampled %>%
ggplot(aes(x,
y,
color = color)) +
geom_point(aes(size = value)) +
scale_color_identity() +
scale_y_reverse() +
scale_size(range = c(1, 6)) +
coord_equal(expand = FALSE) +
theme_void() +
theme(legend.position = "none")
ggsave("snowscape-circles.png")
Saving 7.29 x 4.51 in image

Plot with different shape:
snowscape_sampled %>%
ggplot(aes(x,
y,
color = color)) +
geom_point(aes(size = value),
shape = 17) +
geom_point(size = 0.1,
color = "black",
shape = 20) +
scale_color_identity() +
scale_size(range = c(1, 5)) +
scale_y_reverse() +
coord_equal(expand = FALSE) +
theme_void() +
theme(legend.position = "none")
ggsave("snowscape-dotted-diamonds.png")
Saving 7.29 x 4.51 in image

Retrieve every nth row/column from image:
nx <- 10
ny <- 20
snowscape_sampled <- snowscape_df %>%
filter(x %% nx == 1,
y %% ny == 1)
Define length of segments:
l <- 15 # Experiment with the length
Create and plot the flow field:
n_min <- min(snowscape_sampled$x)
n_max <- max(snowscape_sampled$x)
# Offsets
x_o <- -max(snowscape_sampled$x)/2 # Experiment with the sign and the fraction
y_o <- 0 #max(snowscape_sampled$y)
df <- snowscape_sampled %>%
mutate(angle = 1 * pi/6 * (1 -(x - x_o)/(n_max - n_min)),
xend = (x + l * cos(angle)),
yend = (y + l * sin(angle)))
df %>%
ggplot() +
geom_segment(aes(x = x,
y = y,
xend = xend,
yend = yend,
size = value,
color = color)) +
scale_size(range = c(1, 8)) + # Experiment with the range
scale_color_identity() +
scale_y_reverse() +
coord_equal(expand = FALSE) +
theme_void() +
theme(legend.position = "none")
ggsave("snowscape-flow-field.png")
Saving 7.29 x 4.51 in image

Process image - Meghan
Read the image using imager::load.image():
meghan <- load.image("meghan.jpg")
Check the size of the image:
summary(meghan)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.0000 0.2980 0.6510 0.5623 0.8118 1.0000
Convert image to data frame (still working with {imager}):
meghan_df <- meghan %>%
as.data.frame(wide="c") %>%
mutate(color = rgb(c.1,
c.2,
c.3))
Convert to grayscale and to data frame:
meghan_df_grayscale <- meghan %>%
grayscale() %>%
as.data.frame()
Join data frames with color and grayscale values:
meghan_df <- meghan_df %>%
left_join(meghan_df_grayscale,
by = c("x", "y"))
Crop image:
meghan_df <- meghan_df %>%
filter(x <= 1250, y <= 1250)
Retrieve every nth row/column from image:
nx <- 20
ny <- 20
meghan_sampled <- meghan_df %>%
filter(x %% nx == 1,
y %% ny == 1)
Plot:
meghan_sampled %>%
ggplot() +
geom_point(aes(x,
y,
color = value),
shape = 15,
size = 6) +
scale_color_fermenter(palette = "greens") +
new_scale_color() +
geom_point(aes(x,
y,
color = color,
size = value)) +
scale_color_identity() +
scale_y_reverse() +
scale_size(range = c(0.1, 3)) +
coord_equal(expand = FALSE) +
theme_void() +
theme(legend.position = "none")
Warning in pal_name(palette, type) : Unknown palette greens
ggsave("meghan-circles.png",
height = 8,
width = 8,
units = "in")

Plot with different shape:
meghan_sampled %>%
ggplot() +
geom_point(aes(x,
y),
color = "black",
shape = 15,
size = 6) +
geom_point(aes(x,
y,
color = color,
size = value),
shape = 17) +
# geom_point(aes(x,
# y),
# size = 0.1,
# color = "black",
# shape = 20) +
scale_color_identity() +
scale_size(range = c(1, 4)) +
scale_y_reverse() +
coord_equal(expand = FALSE) +
theme_void() +
theme(legend.position = "none")
ggsave("meghan-diamonds.png",
height = 8,
width = 8,
units = "in")

Retrieve every nth row/column from image:
nx <- 25
ny <- 25
meghan_sampled <- meghan_df %>%
filter(x %% nx == 1,
y %% ny == 1)
Define length of segments:
l <- 25 # Experiment with the length
Create and plot the flow field:
n_min <- min(meghan_sampled$x)
n_max <- max(meghan_sampled$x)
# Offsets
x_o <- 0 #max(meghan_sampled$x)/2 # Experiment with the sign and the fraction
y_o <- 0 #max(meghan_sampled$y)
# Initial rotation
init_r <- 1/8
df <- meghan_sampled %>%
mutate(angle = ((x - x_o) * (y - y_o)) /(n_max - n_min)^2 * 2 * pi + init_r * pi,
xend = (x + l * cos(angle)),
yend = (y + l * sin(angle)))
df %>%
ggplot() +
geom_point(aes(x,
y,
color = value),
#color = "black",
shape = 15,
size = 6) +
scale_color_fermenter(palette = "Greys") +
new_scale_color() +
geom_segment(aes(x = x,
y = y,
xend = xend,
yend = yend,
size = value,
color = color)) +
scale_size(range = c(0.5, 3)) + # Experiment with the range
scale_color_identity() +
scale_y_reverse() +
coord_equal(expand = FALSE) +
theme_void() +
theme(legend.position = "none")
ggsave("meghan-flow-field.png",
height = 8,
width = 8,
units = "in")

Process image - Mariana
Read the image using imager::load.image():
mariana <- load.image("mariana-gato.jpg")
Check the size of the image:
summary(mariana)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.0000 0.2784 0.4353 0.4709 0.6784 1.0000
Convert image to data frame (still working with {imager}):
mariana_df <- mariana %>%
as.data.frame(wide="c") %>%
mutate(color = rgb(c.1,
c.2,
c.3))
Convert to grayscale and to data frame:
mariana_df_grayscale <- mariana %>%
grayscale() %>%
as.data.frame()
Join data frames with color and grayscale values:
mariana_df <- mariana_df %>%
left_join(mariana_df_grayscale,
by = c("x", "y"))
Crop image:
#mariana_df <- mariana_df %>%
# filter(x <= 1250, y <= 1250)
Retrieve every nth row/column from image:
nx <- 30
ny <- 30
mariana_sampled <- mariana_df %>%
filter(x %% nx == 1,
y %% ny == 1)
Plot:
mariana_sampled %>%
ggplot() +
geom_point(aes(x,
y,
color = value),
shape = 15,
size = 6) +
scale_color_fermenter(palette = "Greys") +
new_scale_color() +
geom_point(aes(x,
y,
color = color,
size = value)) +
scale_color_identity() +
scale_y_reverse() +
scale_size(range = c(0.1, 3)) +
coord_equal(expand = FALSE) +
theme_void() +
theme(legend.position = "none")

# ggsave("meghan-circles.png",
# height = 8,
# width = 8,
# units = "in")
Plot with different shape:
mariana_sampled %>%
ggplot() +
geom_point(aes(x,
y),
color = "black",
shape = 15,
size = 6) +
geom_point(aes(x,
y,
color = color,
size = value),
shape = 17) +
# geom_point(aes(x,
# y),
# size = 0.1,
# color = "black",
# shape = 20) +
scale_color_identity() +
scale_size(range = c(1, 4)) +
scale_y_reverse() +
coord_equal(expand = FALSE) +
theme_void() +
theme(legend.position = "none")

# ggsave("meghan-diamonds.png",
# height = 8,
# width = 8,
# units = "in")
Retrieve every nth row/column from image:
nx <- 25
ny <- 25
mariana_sampled <- mariana_df %>%
filter(x %% nx == 1,
y %% ny == 1)
Define length of segments:
l <- 25 # Experiment with the length
Create and plot the flow field:
n_min <- min(meghan_sampled$x)
n_max <- max(meghan_sampled$x)
# Offsets
x_o <- 0 #max(meghan_sampled$x)/2 # Experiment with the sign and the fraction
y_o <- 0 #max(meghan_sampled$y)
# Initial rotation
init_r <- 1/8
df <- mariana_sampled %>%
mutate(angle = ((x - x_o) * (y - y_o)) /(n_max - n_min)^2 * 2 * pi + init_r * pi,
xend = (x + l * cos(angle)),
yend = (y + l * sin(angle)))
df %>%
ggplot() +
geom_point(aes(x,
y,
color = value),
color = "black",
shape = 15,
size = 6) +
scale_color_distiller(palette = "Greys") +
new_scale_color() +
geom_segment(aes(x = x,
y = y,
xend = xend,
yend = yend,
size = value,
color = color)) +
scale_size(range = c(0.5, 3)) + # Experiment with the range
scale_color_identity() +
scale_y_reverse() +
coord_equal(expand = FALSE) +
theme_void() +
theme(legend.position = "none")
ggsave("mariana-flow-field.png",
height = 8,
width = 8,
units = "in")

Process image - Oregon
Read the image using imager::load.image():
oregon <- load.image("oregon.jpg")
Check the size of the image:
summary(oregon)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.0000 0.3137 0.4627 0.4681 0.6157 1.0000
Convert image to data frame (still working with {imager}):
oregon_df <- oregon %>%
as.data.frame(wide="c") %>%
mutate(color = rgb(c.1,
c.2,
c.3))
Convert to grayscale and to data frame:
oregon_df_grayscale <- oregon %>%
grayscale() %>%
as.data.frame()
Join data frames with color and grayscale values:
oregon_df <- oregon_df %>%
left_join(oregon_df_grayscale,
by = c("x", "y"))
Retrieve every nth row/column from image:
nx <- 10
ny <- 10
oregon_sampled <- oregon_df %>%
filter(x %% nx == 1,
y %% ny == 1)
Create and plot the flow field:
# Offsets
x_o <- 560
y_o <- 140
df <- oregon_sampled %>%
#length of segments depends on position, and the angle is constant from x_o, y_o
mutate(xend = (x + (x - x_o)/30 * pi/4),
yend = (y + (y - y_o)/30 * pi/4))
df %>%
ggplot() +
geom_point(aes(x,
y,
color = value),
shape = 15,
size = 6) +
scale_color_distiller(palette = "Greys") +
new_scale_color() +
geom_segment(aes(x = x,
y = y,
xend = xend,
yend = yend,
size = value,
color = color)) +
scale_size(range = c(0.1, 2)) + # Experiment with the range
scale_color_identity() +
scale_y_reverse() +
coord_equal(expand = FALSE) +
theme_void() +
theme(legend.position = "none")
ggsave("oregon-flow-field.png",
height = 8,
width = 8,
units = "in")

Waldport
See https://twitter.com/mark_lawler/status/1490467641676337154/photo/2 for this image: 
Read the image using imager::load.image():
waldport <- load.image("waldport.jpg")
Check the size of the image:
summary(waldport)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.0000 0.2235 0.4235 0.4616 0.6902 1.0000
Convert image to data frame (still working with {imager}):
waldport_df <- waldport %>%
as.data.frame(wide="c") %>%
mutate(color = rgb(c.1,
c.2,
c.3))
Convert to grayscale and to data frame:
waldport_df_grayscale <- waldport %>%
grayscale() %>%
as.data.frame()
Join data frames with color and grayscale values:
waldport_df <- waldport_df %>%
left_join(waldport_df_grayscale,
by = c("x", "y"))
Retrieve every nth row/column from image:
nx <- 20
ny <- 20
waldport_sampled <- waldport_df %>%
filter(x %% nx == 1,
y %% ny == 1)
Create and plot the flow field:
# Offsets
x_o <- -1000
y_o <- 770
df <- waldport_sampled %>%
#length of segments depends on position, and the angle is constant from x_o, y_o
mutate(xend = (x + (x - x_o)/20 * pi/8),
yend = (y + (y - y_o)/20 * pi/8))
df %>%
ggplot() +
geom_point(aes(x,
y,
color = rev(y)),
shape = 15,
size = 6) +
scale_color_gradientn(colors = MexBrewer::mex.brewer("Atentado")) +
new_scale_color() +
geom_segment(aes(x = x,
y = y,
xend = xend,
yend = yend,
size = value,
color = color)) +
scale_size(range = c(0.01, 0.75)) + # Experiment with the range
scale_color_identity() +
scale_y_reverse() +
coord_equal(expand = FALSE) +
theme_void() +
theme(legend.position = "none")
ggsave("waldport-flow-field.png",
height = 8,
width = 8,
units = "in")

Flower 1 and spirals

Read the image using imager::load.image():
flower <- load.image("flower.jpg")
Check the size of the image:
flower
Image. Width: 720 pix Height: 960 pix Depth: 1 Colour channels: 3
Convert image to data frame (still working with {imager}):
flower_df <- flower %>%
as.data.frame(wide="c") %>%
mutate(color = rgb(c.1,
c.2,
c.3))
Convert to grayscale and to data frame:
flower_df_grayscale <- flower %>%
grayscale() %>%
as.data.frame()
Join data frames with color and grayscale values:
flower_df <- flower_df %>%
left_join(flower_df_grayscale,
by = c("x", "y"))
Convert the image to sf to use sf functions to find nearest features to borrow colors:
flower_sf <- flower_df %>%
st_as_sf(coords = c("x", "y"))
Golden spiral:
#points <- 500
# Defining the Golden Angle
angle <- pi * (3 - sqrt(5))
#t_o <- seq(1, 10, 1)
gs <- data.frame(t_o = seq(1, 750, 0.1) * angle) %>%
mutate(x_o = 300 + t_o * sin(t_o),
y_o = 300 + t_o * cos(t_o),
x_end = x_o + 20 * sin(t_o),
y_end = y_o + 20 * cos(t_o))
Convert to sf to borrow the colors from the image:
gs <- gs %>%
mutate(x = x_o,
y = y_o) %>%
st_as_sf(coords = c("x", "y"))
Find the nearest feature in the original image to borrow the colors:
flower_colors <- flower_df[gs %>%
st_nearest_feature(flower_sf),]
Bind the colors to the packed circles:
gs <- gs %>%
mutate(color = flower_colors$color,
value = flower_colors$value)
Plot:
# Make a scatter plot of points in a spiral
ggplot() +
geom_point(data= flower_df,
aes(x,
y,
color = value),
#color = "black",
shape = 15,
size = 6) +
scale_color_gradientn(colors = MexBrewer::mex.brewer("Atentado")) +
#scale_color_distiller(palette = "Blues") +
new_scale_color() +
geom_segment(data = gs %>%
filter(x_o > 10 & x_o < 710,
y_o > 10 & y_o < 950),
aes(x = x_o,
xend = x_end,
y = y_o,
yend = y_end,
size = t_o,
color = color)) +
scale_y_reverse() +
scale_color_identity() +
scale_size(range = c(0.1, 3)) +
coord_equal() +
theme_void() +
theme(legend.position = "none")
ggsave("flower-flow-field.png",
height = 8,
width = 8,
units = "in")

Flower 2 and spirals

Read the image using imager::load.image():
flower <- load.image("flower-2.jpg")
Check the size of the image:
flower
Image. Width: 720 pix Height: 960 pix Depth: 1 Colour channels: 3
Convert image to data frame (still working with {imager}):
flower_df <- flower %>%
as.data.frame(wide="c") %>%
mutate(color = rgb(c.1,
c.2,
c.3))
Convert to grayscale and to data frame:
flower_df_grayscale <- flower %>%
grayscale() %>%
as.data.frame()
Join data frames with color and grayscale values:
flower_df <- flower_df %>%
left_join(flower_df_grayscale,
by = c("x", "y"))
Convert the image to sf to use sf functions to find nearest features to borrow colors:
flower_sf <- flower_df %>%
st_as_sf(coords = c("x", "y"))
Golden spiral:
#points <- 500
# Defining the Golden Angle
angle <- pi * (3 - sqrt(5))
#t_o <- seq(1, 10, 1)
gs <- data.frame(t_o = seq(1, 750, 0.1) * angle) %>%
mutate(x_o = 160 + t_o * sin(t_o),
y_o = 310 + t_o * cos(t_o),
x_end = x_o + 20 * sin(t_o),
y_end = y_o + 20 * cos(t_o))
Convert to sf to borrow the colors from the image:
gs <- gs %>%
mutate(x = x_o,
y = y_o) %>%
st_as_sf(coords = c("x", "y"))
Find the nearest feature in the original image to borrow the colors:
flower_colors <- flower_df[gs %>%
st_nearest_feature(flower_sf),]
Bind the colors to the spiral:
gs <- gs %>%
mutate(color = flower_colors$color,
value = flower_colors$value)
Plot:
# Make a scatter plot of points in a spiral
ggplot() +
# geom_point(data= flower_df,
# aes(x,
# y,
# color = value),
# #color = "black",
# shape = 15,
# size = 6) +
# scale_color_gradientn(colors = MexBrewer::mex.brewer("Atentado")) +
# scale_color_distiller(palette = "Blues") +
# new_scale_color() +
geom_segment(data = gs %>%
filter(x_o > 10 & x_o < 710,
y_o > 10 & y_o < 950),
aes(x = x_o,
xend = x_end,
y = y_o,
yend = y_end,
size = t_o,
color = color)) +
scale_y_reverse() +
scale_color_identity() +
scale_size(range = c(0.1, 3)) +
coord_equal() +
theme_void() +
theme(legend.position = "none")
ggsave("flower-2-flow-field.png",
height = 8,
width = 8,
units = "in")

Polar equation: \[
\rho = a \tan(n\theta)
\] or: \[
\rho = a \cot(n\theta)
\] with \(n>0\). Each curve is obtained for: \[
-\frac{\pi}{2n} < \theta < \frac{\pi}{2n}
\]
Create a data frame to calculate the values of the knot function with parameters \(a\) and \(n\). If \(n\) is a rational number \(p/q\), the number of branches is \(2p\) if \(q\) is odd, and \(p\) if \(q\) is even. Each rotation of a branch is by an angle of \(\pi/n\):
# Scale factor
a <- 1
#Extent of values: larger ext means that fewer angles theta will be used in the calculation. If ext == 1 then the whole domain -pi/(2n) to pi/(2n) is used
ext <- 10 # Must be greater than 1
p <- 6
q <- 5
n <- p/q
# Number of branches
nb <- ifelse(q %% 2 == 1, 2 * p, p)
# Initialize data frame
df <- data.frame(t = seq(-pi/(ext * 2 * n),
pi/(ext * 2 * n),
length.out = 180)) %>%
slice(3:178)
df <- df %>%
# Rotation of branches is between 0 and 2 * pi (which replicates zero); the step increments are the 2 * pi divided by number of branches
cbind(k = rep(seq(0, 2 * pi * (1 - 1/nb), by = 2 * pi/nb), each = nrow(df))) %>%
# Calculate polar coordinates and then convert to cartesian coordinates
mutate(r = a * tan(n * (t + k)),
x = r * cos(t + k),
y = r * sin(t + k)) #%>%
# # Rotation
# mutate(x = x * cos(k) - y * sin(k),
# y = x * sin(k) + y * cos(k))
Plot:
ggplot() +
geom_point(data = df,
aes(x,
y,
color = factor(k))) +
coord_equal()

Parametric equations: \[
x = a(t\cos(t) + kt)
\] and: \[
y = at\sin(t)
\]
Create a data frame to calculate the values of the spiral with parameters \(a\) and \(k\):
# Scale factor
a <- 3
k <- 0.5
# Initialize data frame
df <- data.frame(t = seq(0,
150,
length.out = 300)) %>%
# Calculate polar coordinates and then convert to cartesian coordinates
mutate(x = a * (t * cos(t) + k * t),
y = a * t * sin(t),
x_end = x - 20 * cos(t),
y_end = y + 20 * sin(t))
Plot:
ggplot() +
geom_point(data = df,
aes(x,
y,
color = t)) +
geom_segment(data = df,
aes(x,
y,
xend = x_end,
yend = y_end)) +
coord_equal()

Flowers and spirals

Read the image using imager::load.image():
flower <- load.image("flowers-titi.jpg")
Check the size of the image:
flower
Image. Width: 960 pix Height: 640 pix Depth: 1 Colour channels: 3
Convert image to data frame (still working with {imager}):
flower_df <- flower %>%
as.data.frame(wide="c") %>%
mutate(color = rgb(c.1,
c.2,
c.3))
Convert to grayscale and to data frame:
flower_df_grayscale <- flower %>%
grayscale() %>%
as.data.frame()
Join data frames with color and grayscale values:
flower_df <- flower_df %>%
left_join(flower_df_grayscale,
by = c("x", "y"))
Convert the image to sf to use sf functions to find nearest features to borrow colors:
flower_sf <- flower_df %>%
st_as_sf(coords = c("x", "y"))
Create a data frame to calculate the values of the spiral with parameters \(a\) and \(k\):
# Scale factor
a <- 0.25
k <- 0.1
# Initialize data frame
ds <- data.frame(t = seq(0,
3500,
length.out = 8000)) %>%
# Calculate polar coordinates and then convert to cartesian coordinates
mutate(x_o = 220 + a * (t * cos(t) + k * t),
y_o = 460 + a * t * sin(t),
x_end = x_o - t/200 * cos(t),
y_end = y_o + t/200 * sin(t))
Convert to sf to borrow the colors from the image:
ds <- ds %>%
mutate(x = x_o,
y = y_o) %>%
st_as_sf(coords = c("x", "y"))
Find the nearest feature in the original image to borrow the colors:
flower_colors <- flower_df[ds %>%
st_nearest_feature(flower_sf),]
Bind the colors to the spiral:
ds <- ds %>%
mutate(color = flower_colors$color,
value = flower_colors$value)
Plot:
# Make a scatter plot of points in a spiral
ggplot() +
geom_point(data= flower_df,
aes(x,
y,
color = value),
#color = "black",
shape = 15,
size = 6) +
scale_color_gradientn(colors = MexBrewer::mex.brewer("Atentado")) +
#scale_color_distiller(palette = "Blues") +
new_scale_color() +
geom_segment(data = ds %>%
filter(x_o > -10 & x_o < 970,
y_o > -10 & y_o < 650),
aes(x = x_o,
xend = x_end,
y = y_o,
yend = y_end,
size = t,
color = color)) +
scale_y_reverse() +
scale_color_identity() +
scale_size(range = c(1, 4)) +
coord_equal() +
theme_void() +
theme(legend.position = "none")
ggsave("flower-titi-flow-field-atentado.png",
height = 8,
width = 8,
units = "in")

Try this (see: https://www.facebook.com/mhernandezarrese/posts/10158652605032825):

And this by Mike Kukucska:

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKSGVyZSBJIGV4cGVyaW1lbnQgd2l0aCBjb21iaW5pbmcgZmxvdyBmaWVsZHMgd2l0aCBpbWFnZXMgKGRpdGhlcmluZykuCgpMb2FkIHBhY2thZ2VzOgpgYGB7cn0KbGlicmFyeShnZ25ld3NjYWxlKQpsaWJyYXJ5KGltYWdlcikKbGlicmFyeShzZikKbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKIyMgUHJvY2VzcyBpbWFnZSAtIHNub3dzY2FwZQoKUmVhZCB0aGUgaW1hZ2UgdXNpbmcgYGltYWdlcjo6bG9hZC5pbWFnZSgpYDoKYGBge3J9CiNtZWx2aWxsZSA8LSBpbWFnZV9yZWFkKCJtZWx2aWxsZV9sZy5qcGciKQpzbm93c2NhcGUgPC0gbG9hZC5pbWFnZSgic25vd3NjYXBlLmpwZyIpCmBgYAoKQ2hlY2sgdGhlIHNpemUgb2YgdGhlIGltYWdlOiAKYGBge3J9CnN1bW1hcnkoc25vd3NjYXBlKQpgYGAKCkNvbnZlcnQgaW1hZ2UgdG8gZGF0YSBmcmFtZSAoc3RpbGwgd29ya2luZyB3aXRoIHtpbWFnZXJ9KToKYGBge3J9CnNub3dzY2FwZV9kZiA8LSBzbm93c2NhcGUgJT4lCiAgYXMuZGF0YS5mcmFtZSh3aWRlPSJjIikgJT4lIAogIG11dGF0ZShjb2xvciA9IHJnYihjLjEsCiAgICAgICAgICAgICAgICAgICAgIGMuMiwKICAgICAgICAgICAgICAgICAgICAgYy4zKSkKYGBgCgpDb252ZXJ0IHRvIGdyYXlzY2FsZSBhbmQgdG8gZGF0YSBmcmFtZToKYGBge3J9CnNub3dzY2FwZV9kZl9ncmF5c2NhbGUgPC0gc25vd3NjYXBlICU+JQogIGdyYXlzY2FsZSgpICU+JSAKICBhcy5kYXRhLmZyYW1lKCkKYGBgCgpKb2luIGRhdGEgZnJhbWVzIHdpdGggY29sb3IgYW5kIGdyYXlzY2FsZSB2YWx1ZXM6CmBgYHtyfQpzbm93c2NhcGVfZGYgPC0gc25vd3NjYXBlX2RmICU+JQogIGxlZnRfam9pbihzbm93c2NhcGVfZGZfZ3JheXNjYWxlLAogICAgICAgICAgICBieSA9IGMoIngiLCAieSIpKQpgYGAKClJldHJpZXZlIGV2ZXJ5IG50aCByb3cvY29sdW1uIGZyb20gaW1hZ2U6CmBgYHtyfQpueCA8LSAxMApueSA8LSAyMAoKc25vd3NjYXBlX3NhbXBsZWQgPC0gc25vd3NjYXBlX2RmICU+JQogIGZpbHRlcih4ICUlIG54ID09IDEsCiAgICAgICAgIHkgJSUgbnkgPT0gMSkgCmBgYAoKUGxvdDoKYGBge3J9CnNub3dzY2FwZV9zYW1wbGVkICU+JQogIGdncGxvdChhZXMoeCwgCiAgICAgICAgICAgICB5LCAKICAgICAgICAgICAgIGNvbG9yID0gY29sb3IpKSArIAogIGdlb21fcG9pbnQoYWVzKHNpemUgPSB2YWx1ZSkpICsgCiAgc2NhbGVfY29sb3JfaWRlbnRpdHkoKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKyAKICBzY2FsZV9zaXplKHJhbmdlID0gYygxLCA2KSkgKwogIGNvb3JkX2VxdWFsKGV4cGFuZCA9IEZBTFNFKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpnZ3NhdmUoInNub3dzY2FwZS1jaXJjbGVzLnBuZyIpCmBgYAoKUGxvdCB3aXRoIGRpZmZlcmVudCBzaGFwZToKYGBge3J9CnNub3dzY2FwZV9zYW1wbGVkICU+JQogIGdncGxvdChhZXMoeCwgCiAgICAgICAgICAgICB5LCAKICAgICAgICAgICAgIGNvbG9yID0gY29sb3IpKSArIAogIGdlb21fcG9pbnQoYWVzKHNpemUgPSB2YWx1ZSksCiAgICAgICAgICAgICBzaGFwZSA9IDE3KSArCiAgZ2VvbV9wb2ludChzaXplID0gMC4xLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgc2hhcGUgPSAyMCkgKwogIHNjYWxlX2NvbG9yX2lkZW50aXR5KCkgKwogIHNjYWxlX3NpemUocmFuZ2UgPSBjKDEsIDUpKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKyAKICBjb29yZF9lcXVhbChleHBhbmQgPSBGQUxTRSkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZ2dzYXZlKCJzbm93c2NhcGUtZG90dGVkLWRpYW1vbmRzLnBuZyIpCmBgYAoKClJldHJpZXZlIGV2ZXJ5IG50aCByb3cvY29sdW1uIGZyb20gaW1hZ2U6CmBgYHtyfQpueCA8LSAxMApueSA8LSAyMAoKc25vd3NjYXBlX3NhbXBsZWQgPC0gc25vd3NjYXBlX2RmICU+JQogIGZpbHRlcih4ICUlIG54ID09IDEsCiAgICAgICAgIHkgJSUgbnkgPT0gMSkgCmBgYAoKRGVmaW5lIGxlbmd0aCBvZiBzZWdtZW50czoKYGBge3J9CmwgPC0gMTUgIyBFeHBlcmltZW50IHdpdGggdGhlIGxlbmd0aApgYGAKCkNyZWF0ZSBhbmQgcGxvdCB0aGUgZmxvdyBmaWVsZDoKYGBge3J9CgpuX21pbiA8LSBtaW4oc25vd3NjYXBlX3NhbXBsZWQkeCkKbl9tYXggPC0gbWF4KHNub3dzY2FwZV9zYW1wbGVkJHgpCgojIE9mZnNldHMKeF9vIDwtIC1tYXgoc25vd3NjYXBlX3NhbXBsZWQkeCkvMiAjIEV4cGVyaW1lbnQgd2l0aCB0aGUgc2lnbiBhbmQgdGhlIGZyYWN0aW9uCnlfbyA8LSAwICNtYXgoc25vd3NjYXBlX3NhbXBsZWQkeSkKCmRmIDwtIHNub3dzY2FwZV9zYW1wbGVkICU+JQogIG11dGF0ZShhbmdsZSA9IDEgKiBwaS82ICogKDEgLSh4IC0geF9vKS8obl9tYXggLSBuX21pbikpLAogICAgICAgICB4ZW5kID0gKHggKyBsICogY29zKGFuZ2xlKSksCiAgICAgICAgIHllbmQgPSAoeSArIGwgKiBzaW4oYW5nbGUpKSkKCmRmICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NlZ21lbnQoYWVzKHggPSB4LAogICAgICAgICAgICAgICAgICAgeSA9IHksCiAgICAgICAgICAgICAgICAgICB4ZW5kID0geGVuZCwKICAgICAgICAgICAgICAgICAgIHllbmQgPSB5ZW5kLAogICAgICAgICAgICAgICAgICAgc2l6ZSA9IHZhbHVlLAogICAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xvcikpICsKICBzY2FsZV9zaXplKHJhbmdlID0gYygxLCA4KSkgKyAjIEV4cGVyaW1lbnQgd2l0aCB0aGUgcmFuZ2UKICBzY2FsZV9jb2xvcl9pZGVudGl0eSgpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgY29vcmRfZXF1YWwoZXhwYW5kID0gRkFMU0UpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmdnc2F2ZSgic25vd3NjYXBlLWZsb3ctZmllbGQucG5nIikKYGBgCgojIyBQcm9jZXNzIGltYWdlIC0gTWVnaGFuCgpSZWFkIHRoZSBpbWFnZSB1c2luZyBgaW1hZ2VyOjpsb2FkLmltYWdlKClgOgpgYGB7cn0KbWVnaGFuIDwtIGxvYWQuaW1hZ2UoIm1lZ2hhbi5qcGciKQpgYGAKCkNoZWNrIHRoZSBzaXplIG9mIHRoZSBpbWFnZTogCmBgYHtyfQpzdW1tYXJ5KG1lZ2hhbikKYGBgCgpDb252ZXJ0IGltYWdlIHRvIGRhdGEgZnJhbWUgKHN0aWxsIHdvcmtpbmcgd2l0aCB7aW1hZ2VyfSk6CmBgYHtyfQptZWdoYW5fZGYgPC0gbWVnaGFuICU+JQogIGFzLmRhdGEuZnJhbWUod2lkZT0iYyIpICU+JSAKICBtdXRhdGUoY29sb3IgPSByZ2IoYy4xLAogICAgICAgICAgICAgICAgICAgICBjLjIsCiAgICAgICAgICAgICAgICAgICAgIGMuMykpCmBgYAoKQ29udmVydCB0byBncmF5c2NhbGUgYW5kIHRvIGRhdGEgZnJhbWU6CmBgYHtyfQptZWdoYW5fZGZfZ3JheXNjYWxlIDwtIG1lZ2hhbiAlPiUKICBncmF5c2NhbGUoKSAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpCmBgYAoKSm9pbiBkYXRhIGZyYW1lcyB3aXRoIGNvbG9yIGFuZCBncmF5c2NhbGUgdmFsdWVzOgpgYGB7cn0KbWVnaGFuX2RmIDwtIG1lZ2hhbl9kZiAlPiUKICBsZWZ0X2pvaW4obWVnaGFuX2RmX2dyYXlzY2FsZSwKICAgICAgICAgICAgYnkgPSBjKCJ4IiwgInkiKSkKYGBgCgpDcm9wIGltYWdlOgpgYGB7cn0KbWVnaGFuX2RmIDwtIG1lZ2hhbl9kZiAlPiUKICBmaWx0ZXIoeCA8PSAxMjUwLCB5IDw9IDEyNTApCmBgYAoKUmV0cmlldmUgZXZlcnkgbnRoIHJvdy9jb2x1bW4gZnJvbSBpbWFnZToKYGBge3J9Cm54IDwtIDIwCm55IDwtIDIwCgptZWdoYW5fc2FtcGxlZCA8LSBtZWdoYW5fZGYgJT4lCiAgZmlsdGVyKHggJSUgbnggPT0gMSwKICAgICAgICAgeSAlJSBueSA9PSAxKSAKYGBgCgpQbG90OgpgYGB7cn0KbWVnaGFuX3NhbXBsZWQgJT4lCiAgZ2dwbG90KCkgKyAKICBnZW9tX3BvaW50KGFlcyh4LCAKICAgICAgICAgICAgICAgICB5LAogICAgICAgICAgICAgICAgIGNvbG9yID0gdmFsdWUpLAogICAgICAgICAgICAgc2hhcGUgPSAxNSwKICAgICAgICAgICAgIHNpemUgPSA2KSArCiAgc2NhbGVfY29sb3JfZmVybWVudGVyKHBhbGV0dGUgPSAiZ3JlZW5zIikgKwogIG5ld19zY2FsZV9jb2xvcigpICsKICBnZW9tX3BvaW50KGFlcyh4LCAKICAgICAgICAgICAgICAgICB5LCAKICAgICAgICAgICAgICAgICBjb2xvciA9IGNvbG9yLAogICAgICAgICAgICAgICAgIHNpemUgPSB2YWx1ZSkpICsgCiAgc2NhbGVfY29sb3JfaWRlbnRpdHkoKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKyAKICBzY2FsZV9zaXplKHJhbmdlID0gYygwLjEsIDMpKSArCiAgY29vcmRfZXF1YWwoZXhwYW5kID0gRkFMU0UpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmdnc2F2ZSgibWVnaGFuLWNpcmNsZXMucG5nIiwKICAgICAgIGhlaWdodCA9IDgsCiAgICAgICB3aWR0aCA9IDgsCiAgICAgICB1bml0cyA9ICJpbiIpCmBgYAoKUGxvdCB3aXRoIGRpZmZlcmVudCBzaGFwZToKYGBge3J9Cm1lZ2hhbl9zYW1wbGVkICU+JQogIGdncGxvdCgpICsgCiAgZ2VvbV9wb2ludChhZXMoeCwKICAgICAgICAgICAgICAgICB5KSwKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgIHNoYXBlID0gMTUsCiAgICAgICAgICAgICBzaXplID0gNikgKwogIGdlb21fcG9pbnQoYWVzKHgsIAogICAgICAgICAgICAgICAgIHksCiAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xvciwKICAgICAgICAgICAgICAgICBzaXplID0gdmFsdWUpLAogICAgICAgICAgICAgc2hhcGUgPSAxNykgKwogICMgZ2VvbV9wb2ludChhZXMoeCwgCiAgIyAgICAgICAgICAgIHkpLAogICMgICAgICAgICAgICBzaXplID0gMC4xLAogICMgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgIyAgICAgICAgICAgIHNoYXBlID0gMjApICsKICBzY2FsZV9jb2xvcl9pZGVudGl0eSgpICsKICBzY2FsZV9zaXplKHJhbmdlID0gYygxLCA0KSkgKwogIHNjYWxlX3lfcmV2ZXJzZSgpICsgCiAgY29vcmRfZXF1YWwoZXhwYW5kID0gRkFMU0UpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmdnc2F2ZSgibWVnaGFuLWRpYW1vbmRzLnBuZyIsCiAgICAgICBoZWlnaHQgPSA4LAogICAgICAgd2lkdGggPSA4LAogICAgICAgdW5pdHMgPSAiaW4iKQpgYGAKClJldHJpZXZlIGV2ZXJ5IG50aCByb3cvY29sdW1uIGZyb20gaW1hZ2U6CmBgYHtyfQpueCA8LSAyNQpueSA8LSAyNQoKbWVnaGFuX3NhbXBsZWQgPC0gbWVnaGFuX2RmICU+JQogIGZpbHRlcih4ICUlIG54ID09IDEsCiAgICAgICAgIHkgJSUgbnkgPT0gMSkgCmBgYAoKRGVmaW5lIGxlbmd0aCBvZiBzZWdtZW50czoKYGBge3J9CmwgPC0gMjUgIyBFeHBlcmltZW50IHdpdGggdGhlIGxlbmd0aApgYGAKCkNyZWF0ZSBhbmQgcGxvdCB0aGUgZmxvdyBmaWVsZDoKYGBge3J9Cm5fbWluIDwtIG1pbihtZWdoYW5fc2FtcGxlZCR4KQpuX21heCA8LSBtYXgobWVnaGFuX3NhbXBsZWQkeCkKCiMgT2Zmc2V0cwp4X28gPC0gMCAjbWF4KG1lZ2hhbl9zYW1wbGVkJHgpLzIgIyBFeHBlcmltZW50IHdpdGggdGhlIHNpZ24gYW5kIHRoZSBmcmFjdGlvbgp5X28gPC0gMCAjbWF4KG1lZ2hhbl9zYW1wbGVkJHkpCiMgSW5pdGlhbCByb3RhdGlvbgppbml0X3IgPC0gMS84CgoKZGYgPC0gbWVnaGFuX3NhbXBsZWQgJT4lCiAgbXV0YXRlKGFuZ2xlID0gKCh4IC0geF9vKSAqICh5IC0geV9vKSkgLyhuX21heCAtIG5fbWluKV4yICogMiAqIHBpICsgaW5pdF9yICogcGksCiAgICAgICAgIHhlbmQgPSAoeCArIGwgKiBjb3MoYW5nbGUpKSwKICAgICAgICAgeWVuZCA9ICh5ICsgbCAqIHNpbihhbmdsZSkpKQoKZGYgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoYWVzKHgsCiAgICAgICAgICAgICAgICAgeSwgCiAgICAgICAgICAgICAgICAgY29sb3IgPSB2YWx1ZSksCiAgICAgICAgICAgICAjY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgc2hhcGUgPSAxNSwKICAgICAgICAgICAgIHNpemUgPSA2KSArCiAgc2NhbGVfY29sb3JfZmVybWVudGVyKHBhbGV0dGUgPSAiR3JleXMiKSArCiAgbmV3X3NjYWxlX2NvbG9yKCkgKwogIGdlb21fc2VnbWVudChhZXMoeCA9IHgsCiAgICAgICAgICAgICAgICAgICB5ID0geSwKICAgICAgICAgICAgICAgICAgIHhlbmQgPSB4ZW5kLAogICAgICAgICAgICAgICAgICAgeWVuZCA9IHllbmQsCiAgICAgICAgICAgICAgICAgICBzaXplID0gdmFsdWUsCiAgICAgICAgICAgICAgICAgICBjb2xvciA9IGNvbG9yKSkgKwogIHNjYWxlX3NpemUocmFuZ2UgPSBjKDAuNSwgMykpICsgIyBFeHBlcmltZW50IHdpdGggdGhlIHJhbmdlCiAgc2NhbGVfY29sb3JfaWRlbnRpdHkoKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKwogIGNvb3JkX2VxdWFsKGV4cGFuZCA9IEZBTFNFKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpnZ3NhdmUoIm1lZ2hhbi1mbG93LWZpZWxkLnBuZyIsCiAgICAgICBoZWlnaHQgPSA4LAogICAgICAgd2lkdGggPSA4LAogICAgICAgdW5pdHMgPSAiaW4iKQpgYGAKCiMjIFByb2Nlc3MgaW1hZ2UgLSBNYXJpYW5hCgpSZWFkIHRoZSBpbWFnZSB1c2luZyBgaW1hZ2VyOjpsb2FkLmltYWdlKClgOgpgYGB7cn0KbWFyaWFuYSA8LSBsb2FkLmltYWdlKCJtYXJpYW5hLWdhdG8uanBnIikKYGBgCgpDaGVjayB0aGUgc2l6ZSBvZiB0aGUgaW1hZ2U6IApgYGB7cn0Kc3VtbWFyeShtYXJpYW5hKQpgYGAKCkNvbnZlcnQgaW1hZ2UgdG8gZGF0YSBmcmFtZSAoc3RpbGwgd29ya2luZyB3aXRoIHtpbWFnZXJ9KToKYGBge3J9Cm1hcmlhbmFfZGYgPC0gbWFyaWFuYSAlPiUKICBhcy5kYXRhLmZyYW1lKHdpZGU9ImMiKSAlPiUgCiAgbXV0YXRlKGNvbG9yID0gcmdiKGMuMSwKICAgICAgICAgICAgICAgICAgICAgYy4yLAogICAgICAgICAgICAgICAgICAgICBjLjMpKQpgYGAKCkNvbnZlcnQgdG8gZ3JheXNjYWxlIGFuZCB0byBkYXRhIGZyYW1lOgpgYGB7cn0KbWFyaWFuYV9kZl9ncmF5c2NhbGUgPC0gbWFyaWFuYSAlPiUKICBncmF5c2NhbGUoKSAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpCmBgYAoKSm9pbiBkYXRhIGZyYW1lcyB3aXRoIGNvbG9yIGFuZCBncmF5c2NhbGUgdmFsdWVzOgpgYGB7cn0KbWFyaWFuYV9kZiA8LSBtYXJpYW5hX2RmICU+JQogIGxlZnRfam9pbihtYXJpYW5hX2RmX2dyYXlzY2FsZSwKICAgICAgICAgICAgYnkgPSBjKCJ4IiwgInkiKSkKYGBgCgpDcm9wIGltYWdlOgpgYGB7cn0KI21hcmlhbmFfZGYgPC0gbWFyaWFuYV9kZiAlPiUKIyAgZmlsdGVyKHggPD0gMTI1MCwgeSA8PSAxMjUwKQpgYGAKClJldHJpZXZlIGV2ZXJ5IG50aCByb3cvY29sdW1uIGZyb20gaW1hZ2U6CmBgYHtyfQpueCA8LSAzMApueSA8LSAzMAoKbWFyaWFuYV9zYW1wbGVkIDwtIG1hcmlhbmFfZGYgJT4lCiAgZmlsdGVyKHggJSUgbnggPT0gMSwKICAgICAgICAgeSAlJSBueSA9PSAxKSAKYGBgCgpQbG90OgpgYGB7cn0KbWFyaWFuYV9zYW1wbGVkICU+JQogIGdncGxvdCgpICsgCiAgZ2VvbV9wb2ludChhZXMoeCwgCiAgICAgICAgICAgICAgICAgeSwKICAgICAgICAgICAgICAgICBjb2xvciA9IHZhbHVlKSwKICAgICAgICAgICAgIHNoYXBlID0gMTUsCiAgICAgICAgICAgICBzaXplID0gNikgKwogIHNjYWxlX2NvbG9yX2Zlcm1lbnRlcihwYWxldHRlID0gIkdyZXlzIikgKwogIG5ld19zY2FsZV9jb2xvcigpICsKICBnZW9tX3BvaW50KGFlcyh4LCAKICAgICAgICAgICAgICAgICB5LCAKICAgICAgICAgICAgICAgICBjb2xvciA9IGNvbG9yLAogICAgICAgICAgICAgICAgIHNpemUgPSB2YWx1ZSkpICsgCiAgc2NhbGVfY29sb3JfaWRlbnRpdHkoKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKyAKICBzY2FsZV9zaXplKHJhbmdlID0gYygwLjEsIDMpKSArCiAgY29vcmRfZXF1YWwoZXhwYW5kID0gRkFMU0UpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCiMgZ2dzYXZlKCJtZWdoYW4tY2lyY2xlcy5wbmciLAojICAgICAgICBoZWlnaHQgPSA4LAojICAgICAgICB3aWR0aCA9IDgsCiMgICAgICAgIHVuaXRzID0gImluIikKYGBgCgpQbG90IHdpdGggZGlmZmVyZW50IHNoYXBlOgpgYGB7cn0KbWFyaWFuYV9zYW1wbGVkICU+JQogIGdncGxvdCgpICsgCiAgZ2VvbV9wb2ludChhZXMoeCwKICAgICAgICAgICAgICAgICB5KSwKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgIHNoYXBlID0gMTUsCiAgICAgICAgICAgICBzaXplID0gNikgKwogIGdlb21fcG9pbnQoYWVzKHgsIAogICAgICAgICAgICAgICAgIHksCiAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xvciwKICAgICAgICAgICAgICAgICBzaXplID0gdmFsdWUpLAogICAgICAgICAgICAgc2hhcGUgPSAxNykgKwogICMgZ2VvbV9wb2ludChhZXMoeCwgCiAgIyAgICAgICAgICAgIHkpLAogICMgICAgICAgICAgICBzaXplID0gMC4xLAogICMgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgIyAgICAgICAgICAgIHNoYXBlID0gMjApICsKICBzY2FsZV9jb2xvcl9pZGVudGl0eSgpICsKICBzY2FsZV9zaXplKHJhbmdlID0gYygxLCA0KSkgKwogIHNjYWxlX3lfcmV2ZXJzZSgpICsgCiAgY29vcmRfZXF1YWwoZXhwYW5kID0gRkFMU0UpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCiMgZ2dzYXZlKCJtZWdoYW4tZGlhbW9uZHMucG5nIiwKIyAgICAgICAgaGVpZ2h0ID0gOCwKIyAgICAgICAgd2lkdGggPSA4LAojICAgICAgICB1bml0cyA9ICJpbiIpCmBgYAoKUmV0cmlldmUgZXZlcnkgbnRoIHJvdy9jb2x1bW4gZnJvbSBpbWFnZToKYGBge3J9Cm54IDwtIDI1Cm55IDwtIDI1CgptYXJpYW5hX3NhbXBsZWQgPC0gbWFyaWFuYV9kZiAlPiUKICBmaWx0ZXIoeCAlJSBueCA9PSAxLAogICAgICAgICB5ICUlIG55ID09IDEpIApgYGAKCkRlZmluZSBsZW5ndGggb2Ygc2VnbWVudHM6CmBgYHtyfQpsIDwtIDI1ICMgRXhwZXJpbWVudCB3aXRoIHRoZSBsZW5ndGgKYGBgCgpDcmVhdGUgYW5kIHBsb3QgdGhlIGZsb3cgZmllbGQ6CmBgYHtyfQpuX21pbiA8LSBtaW4obWVnaGFuX3NhbXBsZWQkeCkKbl9tYXggPC0gbWF4KG1lZ2hhbl9zYW1wbGVkJHgpCgojIE9mZnNldHMKeF9vIDwtIDAgI21heChtZWdoYW5fc2FtcGxlZCR4KS8yICMgRXhwZXJpbWVudCB3aXRoIHRoZSBzaWduIGFuZCB0aGUgZnJhY3Rpb24KeV9vIDwtIDAgI21heChtZWdoYW5fc2FtcGxlZCR5KQojIEluaXRpYWwgcm90YXRpb24KaW5pdF9yIDwtIDEvOAoKCmRmIDwtIG1hcmlhbmFfc2FtcGxlZCAlPiUKICBtdXRhdGUoYW5nbGUgPSAoKHggLSB4X28pICogKHkgLSB5X28pKSAvKG5fbWF4IC0gbl9taW4pXjIgKiAyICogcGkgKyBpbml0X3IgKiBwaSwKICAgICAgICAgeGVuZCA9ICh4ICsgbCAqIGNvcyhhbmdsZSkpLAogICAgICAgICB5ZW5kID0gKHkgKyBsICogc2luKGFuZ2xlKSkpCgpkZiAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChhZXMoeCwKICAgICAgICAgICAgICAgICB5LCAKICAgICAgICAgICAgICAgICBjb2xvciA9IHZhbHVlKSwKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgIHNoYXBlID0gMTUsCiAgICAgICAgICAgICBzaXplID0gNikgKwogIHNjYWxlX2NvbG9yX2Rpc3RpbGxlcihwYWxldHRlID0gIkdyZXlzIikgKwogIG5ld19zY2FsZV9jb2xvcigpICsKICBnZW9tX3NlZ21lbnQoYWVzKHggPSB4LAogICAgICAgICAgICAgICAgICAgeSA9IHksCiAgICAgICAgICAgICAgICAgICB4ZW5kID0geGVuZCwKICAgICAgICAgICAgICAgICAgIHllbmQgPSB5ZW5kLAogICAgICAgICAgICAgICAgICAgc2l6ZSA9IHZhbHVlLAogICAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xvcikpICsKICBzY2FsZV9zaXplKHJhbmdlID0gYygwLjUsIDMpKSArICMgRXhwZXJpbWVudCB3aXRoIHRoZSByYW5nZQogIHNjYWxlX2NvbG9yX2lkZW50aXR5KCkgKwogIHNjYWxlX3lfcmV2ZXJzZSgpICsKICBjb29yZF9lcXVhbChleHBhbmQgPSBGQUxTRSkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZ2dzYXZlKCJtYXJpYW5hLWZsb3ctZmllbGQucG5nIiwKICAgICAgIGhlaWdodCA9IDgsCiAgICAgICB3aWR0aCA9IDgsCiAgICAgICB1bml0cyA9ICJpbiIpCmBgYAoKIyMgUHJvY2VzcyBpbWFnZSAtIE9yZWdvbgoKUmVhZCB0aGUgaW1hZ2UgdXNpbmcgYGltYWdlcjo6bG9hZC5pbWFnZSgpYDoKYGBge3J9Cm9yZWdvbiA8LSBsb2FkLmltYWdlKCJvcmVnb24uanBnIikKYGBgCgpDaGVjayB0aGUgc2l6ZSBvZiB0aGUgaW1hZ2U6IApgYGB7cn0Kc3VtbWFyeShvcmVnb24pCmBgYAoKQ29udmVydCBpbWFnZSB0byBkYXRhIGZyYW1lIChzdGlsbCB3b3JraW5nIHdpdGgge2ltYWdlcn0pOgpgYGB7cn0Kb3JlZ29uX2RmIDwtIG9yZWdvbiAlPiUKICBhcy5kYXRhLmZyYW1lKHdpZGU9ImMiKSAlPiUgCiAgbXV0YXRlKGNvbG9yID0gcmdiKGMuMSwKICAgICAgICAgICAgICAgICAgICAgYy4yLAogICAgICAgICAgICAgICAgICAgICBjLjMpKQpgYGAKCkNvbnZlcnQgdG8gZ3JheXNjYWxlIGFuZCB0byBkYXRhIGZyYW1lOgpgYGB7cn0Kb3JlZ29uX2RmX2dyYXlzY2FsZSA8LSBvcmVnb24gJT4lCiAgZ3JheXNjYWxlKCkgJT4lIAogIGFzLmRhdGEuZnJhbWUoKQpgYGAKCkpvaW4gZGF0YSBmcmFtZXMgd2l0aCBjb2xvciBhbmQgZ3JheXNjYWxlIHZhbHVlczoKYGBge3J9Cm9yZWdvbl9kZiA8LSBvcmVnb25fZGYgJT4lCiAgbGVmdF9qb2luKG9yZWdvbl9kZl9ncmF5c2NhbGUsCiAgICAgICAgICAgIGJ5ID0gYygieCIsICJ5IikpCmBgYAoKUmV0cmlldmUgZXZlcnkgbnRoIHJvdy9jb2x1bW4gZnJvbSBpbWFnZToKYGBge3J9Cm54IDwtIDEwCm55IDwtIDEwCgpvcmVnb25fc2FtcGxlZCA8LSBvcmVnb25fZGYgJT4lCiAgZmlsdGVyKHggJSUgbnggPT0gMSwKICAgICAgICAgeSAlJSBueSA9PSAxKSAKYGBgCgpDcmVhdGUgYW5kIHBsb3QgdGhlIGZsb3cgZmllbGQ6CmBgYHtyfQojIE9mZnNldHMKeF9vIDwtIDU2MAp5X28gPC0gMTQwCgoKZGYgPC0gb3JlZ29uX3NhbXBsZWQgJT4lCiAgI2xlbmd0aCBvZiBzZWdtZW50cyBkZXBlbmRzIG9uIHBvc2l0aW9uLCBhbmQgdGhlIGFuZ2xlIGlzIGNvbnN0YW50IGZyb20geF9vLCB5X28KICBtdXRhdGUoeGVuZCA9ICh4ICsgKHggLSB4X28pLzMwICogcGkvNCksCiAgICAgICAgIHllbmQgPSAoeSArICh5IC0geV9vKS8zMCAqIHBpLzQpKQoKZGYgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoYWVzKHgsCiAgICAgICAgICAgICAgICAgeSwKICAgICAgICAgICAgICAgICBjb2xvciA9IHZhbHVlKSwKICAgICAgICAgICAgIHNoYXBlID0gMTUsCiAgICAgICAgICAgICBzaXplID0gNikgKwogIHNjYWxlX2NvbG9yX2Rpc3RpbGxlcihwYWxldHRlID0gIkdyZXlzIikgKwogIG5ld19zY2FsZV9jb2xvcigpICsKICBnZW9tX3NlZ21lbnQoYWVzKHggPSB4LAogICAgICAgICAgICAgICAgICAgeSA9IHksCiAgICAgICAgICAgICAgICAgICB4ZW5kID0geGVuZCwKICAgICAgICAgICAgICAgICAgIHllbmQgPSB5ZW5kLAogICAgICAgICAgICAgICAgICAgc2l6ZSA9IHZhbHVlLAogICAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xvcikpICsKICBzY2FsZV9zaXplKHJhbmdlID0gYygwLjEsIDIpKSArICMgRXhwZXJpbWVudCB3aXRoIHRoZSByYW5nZQogIHNjYWxlX2NvbG9yX2lkZW50aXR5KCkgKwogIHNjYWxlX3lfcmV2ZXJzZSgpICsKICBjb29yZF9lcXVhbChleHBhbmQgPSBGQUxTRSkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZ2dzYXZlKCJvcmVnb24tZmxvdy1maWVsZC5wbmciLAogICAgICAgaGVpZ2h0ID0gOCwKICAgICAgIHdpZHRoID0gOCwKICAgICAgIHVuaXRzID0gImluIikKYGBgCgojIyBXYWxkcG9ydAoKU2VlIGh0dHBzOi8vdHdpdHRlci5jb20vbWFya19sYXdsZXIvc3RhdHVzLzE0OTA0Njc2NDE2NzYzMzcxNTQvcGhvdG8vMiBmb3IgdGhpcyBpbWFnZToKIVtdKFdhbGRwb3J0LmpwZykKClJlYWQgdGhlIGltYWdlIHVzaW5nIGBpbWFnZXI6OmxvYWQuaW1hZ2UoKWA6CmBgYHtyfQp3YWxkcG9ydCA8LSBsb2FkLmltYWdlKCJ3YWxkcG9ydC5qcGciKQpgYGAKCkNoZWNrIHRoZSBzaXplIG9mIHRoZSBpbWFnZTogCmBgYHtyfQpzdW1tYXJ5KHdhbGRwb3J0KQpgYGAKCkNvbnZlcnQgaW1hZ2UgdG8gZGF0YSBmcmFtZSAoc3RpbGwgd29ya2luZyB3aXRoIHtpbWFnZXJ9KToKYGBge3J9CndhbGRwb3J0X2RmIDwtIHdhbGRwb3J0ICU+JQogIGFzLmRhdGEuZnJhbWUod2lkZT0iYyIpICU+JSAKICBtdXRhdGUoY29sb3IgPSByZ2IoYy4xLAogICAgICAgICAgICAgICAgICAgICBjLjIsCiAgICAgICAgICAgICAgICAgICAgIGMuMykpCmBgYAoKQ29udmVydCB0byBncmF5c2NhbGUgYW5kIHRvIGRhdGEgZnJhbWU6CmBgYHtyfQp3YWxkcG9ydF9kZl9ncmF5c2NhbGUgPC0gd2FsZHBvcnQgJT4lCiAgZ3JheXNjYWxlKCkgJT4lIAogIGFzLmRhdGEuZnJhbWUoKQpgYGAKCkpvaW4gZGF0YSBmcmFtZXMgd2l0aCBjb2xvciBhbmQgZ3JheXNjYWxlIHZhbHVlczoKYGBge3J9CndhbGRwb3J0X2RmIDwtIHdhbGRwb3J0X2RmICU+JQogIGxlZnRfam9pbih3YWxkcG9ydF9kZl9ncmF5c2NhbGUsCiAgICAgICAgICAgIGJ5ID0gYygieCIsICJ5IikpCmBgYAoKUmV0cmlldmUgZXZlcnkgbnRoIHJvdy9jb2x1bW4gZnJvbSBpbWFnZToKYGBge3J9Cm54IDwtIDIwCm55IDwtIDIwCgp3YWxkcG9ydF9zYW1wbGVkIDwtIHdhbGRwb3J0X2RmICU+JQogIGZpbHRlcih4ICUlIG54ID09IDEsCiAgICAgICAgIHkgJSUgbnkgPT0gMSkgCmBgYAoKQ3JlYXRlIGFuZCBwbG90IHRoZSBmbG93IGZpZWxkOgpgYGB7cn0KIyBPZmZzZXRzCnhfbyA8LSAtMTAwMAp5X28gPC0gNzcwCgoKZGYgPC0gd2FsZHBvcnRfc2FtcGxlZCAlPiUKICAjbGVuZ3RoIG9mIHNlZ21lbnRzIGRlcGVuZHMgb24gcG9zaXRpb24sIGFuZCB0aGUgYW5nbGUgaXMgY29uc3RhbnQgZnJvbSB4X28sIHlfbwogIG11dGF0ZSh4ZW5kID0gKHggKyAoeCAtIHhfbykvMjAgKiBwaS84KSwKICAgICAgICAgeWVuZCA9ICh5ICsgKHkgLSB5X28pLzIwICogcGkvOCkpCgpkZiAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChhZXMoeCwKICAgICAgICAgICAgICAgICB5LAogICAgICAgICAgICAgICAgIGNvbG9yID0gcmV2KHkpKSwKICAgICAgICAgICAgIHNoYXBlID0gMTUsCiAgICAgICAgICAgICBzaXplID0gNikgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBNZXhCcmV3ZXI6Om1leC5icmV3ZXIoIkF0ZW50YWRvIikpICsKICBuZXdfc2NhbGVfY29sb3IoKSArCiAgZ2VvbV9zZWdtZW50KGFlcyh4ID0geCwKICAgICAgICAgICAgICAgICAgIHkgPSB5LAogICAgICAgICAgICAgICAgICAgeGVuZCA9IHhlbmQsCiAgICAgICAgICAgICAgICAgICB5ZW5kID0geWVuZCwKICAgICAgICAgICAgICAgICAgIHNpemUgPSB2YWx1ZSwKICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY29sb3IpKSArCiAgc2NhbGVfc2l6ZShyYW5nZSA9IGMoMC4wMSwgMC43NSkpICsgIyBFeHBlcmltZW50IHdpdGggdGhlIHJhbmdlCiAgc2NhbGVfY29sb3JfaWRlbnRpdHkoKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKwogIGNvb3JkX2VxdWFsKGV4cGFuZCA9IEZBTFNFKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpnZ3NhdmUoIndhbGRwb3J0LWZsb3ctZmllbGQucG5nIiwKICAgICAgIGhlaWdodCA9IDgsCiAgICAgICB3aWR0aCA9IDgsCiAgICAgICB1bml0cyA9ICJpbiIpCmBgYAoKIyMgT25lIG1vcmUgb2YgYW5vdGhlciBiZWFjaCEgQ2hlY2sgdGhpczogaHR0cHM6Ly90d2l0dGVyLmNvbS9HaXVJaWFub0RNZWRpY2kvc3RhdHVzLzE0OTA3MTUxNDAwNTE5NDc1MjEKCiFbXShiZWFjaC5qcGcpCgpSZWFkIHRoZSBpbWFnZSB1c2luZyBgaW1hZ2VyOjpsb2FkLmltYWdlKClgOgpgYGB7cn0KYmVhY2ggPC0gbG9hZC5pbWFnZSgiYmVhY2guanBnIikKYGBgCgpDaGVjayB0aGUgc2l6ZSBvZiB0aGUgaW1hZ2U6IApgYGB7cn0KYmVhY2gKYGBgCgpDb252ZXJ0IGltYWdlIHRvIGRhdGEgZnJhbWUgKHN0aWxsIHdvcmtpbmcgd2l0aCB7aW1hZ2VyfSk6CmBgYHtyfQpiZWFjaF9kZiA8LSBiZWFjaCAlPiUKICBhcy5kYXRhLmZyYW1lKHdpZGU9ImMiKSAlPiUgCiAgbXV0YXRlKGNvbG9yID0gcmdiKGMuMSwKICAgICAgICAgICAgICAgICAgICAgYy4yLAogICAgICAgICAgICAgICAgICAgICBjLjMpKQpgYGAKCkNvbnZlcnQgdG8gZ3JheXNjYWxlIGFuZCB0byBkYXRhIGZyYW1lOgpgYGB7cn0KYmVhY2hfZGZfZ3JheXNjYWxlIDwtIGJlYWNoICU+JQogIGdyYXlzY2FsZSgpICU+JSAKICBhcy5kYXRhLmZyYW1lKCkKYGBgCgpKb2luIGRhdGEgZnJhbWVzIHdpdGggY29sb3IgYW5kIGdyYXlzY2FsZSB2YWx1ZXM6CmBgYHtyfQpiZWFjaF9kZiA8LSBiZWFjaF9kZiAlPiUKICBsZWZ0X2pvaW4oYmVhY2hfZGZfZ3JheXNjYWxlLAogICAgICAgICAgICBieSA9IGMoIngiLCAieSIpKQpgYGAKClJldHJpZXZlIGV2ZXJ5IG50aCByb3cvY29sdW1uIGZyb20gaW1hZ2U6CmBgYHtyfQpueCA8LSAxMApueSA8LSAxMAoKYmVhY2hfc2FtcGxlZCA8LSBiZWFjaF9kZiAlPiUKICBmaWx0ZXIoeCAlJSBueCA9PSAxLAogICAgICAgICB5ICUlIG55ID09IDEpIApgYGAKCkNyZWF0ZSBhbmQgcGxvdCB0aGUgZmxvdyBmaWVsZDoKYGBge3J9CiMgT2Zmc2V0cwp4X28gPC0gMjAwCnlfbyA8LSA0ODAKCgpkZiA8LSBiZWFjaF9zYW1wbGVkICU+JQogICNsZW5ndGggb2Ygc2VnbWVudHMgZGVwZW5kcyBvbiBwb3NpdGlvbiwgYW5kIHRoZSBhbmdsZSBpcyBjb25zdGFudCBmcm9tIHhfbywgeV9vCiAgbXV0YXRlKHhlbmQgPSAoeCArICh4IC0geF9vKS8yMCAqIHBpLzQpLAogICAgICAgICB5ZW5kID0gKHkgKyAoeSAtIHlfbykvMjAgKiBwaS80KSkKCmRmICU+JQogIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGFlcyh4LAogICAgICAgICAgICAgICAgIHksCiAgICAgICAgICAgICAgICAgY29sb3IgPSByZXYoeSkpLAogICAgICAgICAgICAgc2hhcGUgPSAxNSwKICAgICAgICAgICAgIHNpemUgPSA2KSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IE1leEJyZXdlcjo6bWV4LmJyZXdlcigiQXRlbnRhZG8iKSkgKwogIG5ld19zY2FsZV9jb2xvcigpICsKICBnZW9tX3NlZ21lbnQoYWVzKHggPSB4LAogICAgICAgICAgICAgICAgICAgeSA9IHksCiAgICAgICAgICAgICAgICAgICB4ZW5kID0geGVuZCwKICAgICAgICAgICAgICAgICAgIHllbmQgPSB5ZW5kLAogICAgICAgICAgICAgICAgICAgc2l6ZSA9IHNxcnQoKHggLSB4X28pXjIgKyAoeSAtIHlfbyleMiksCiAgICAgICAgICAgICAgICAgICBjb2xvciA9IGNvbG9yKSkgKwogIHNjYWxlX3NpemUocmFuZ2UgPSBjKDAuNSwgMS41KSkgKyAjIEV4cGVyaW1lbnQgd2l0aCB0aGUgcmFuZ2UKICBzY2FsZV9jb2xvcl9pZGVudGl0eSgpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgY29vcmRfZXF1YWwoZXhwYW5kID0gRkFMU0UpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmdnc2F2ZSgiYmVhY2gtZmxvdy1maWVsZC5wbmciLAogICAgICAgaGVpZ2h0ID0gOCwKICAgICAgIHdpZHRoID0gOCwKICAgICAgIHVuaXRzID0gImluIikKYGBgCgojIyBGbG93ZXIgMSBhbmQgc3BpcmFscwoKIVtdKGZsb3dlci5qcGcpCgpSZWFkIHRoZSBpbWFnZSB1c2luZyBgaW1hZ2VyOjpsb2FkLmltYWdlKClgOgpgYGB7cn0KZmxvd2VyIDwtIGxvYWQuaW1hZ2UoImZsb3dlci5qcGciKQpgYGAKCkNoZWNrIHRoZSBzaXplIG9mIHRoZSBpbWFnZTogCmBgYHtyfQpmbG93ZXIKYGBgCgpDb252ZXJ0IGltYWdlIHRvIGRhdGEgZnJhbWUgKHN0aWxsIHdvcmtpbmcgd2l0aCB7aW1hZ2VyfSk6CmBgYHtyfQpmbG93ZXJfZGYgPC0gZmxvd2VyICU+JQogIGFzLmRhdGEuZnJhbWUod2lkZT0iYyIpICU+JSAKICBtdXRhdGUoY29sb3IgPSByZ2IoYy4xLAogICAgICAgICAgICAgICAgICAgICBjLjIsCiAgICAgICAgICAgICAgICAgICAgIGMuMykpCmBgYAoKQ29udmVydCB0byBncmF5c2NhbGUgYW5kIHRvIGRhdGEgZnJhbWU6CmBgYHtyfQpmbG93ZXJfZGZfZ3JheXNjYWxlIDwtIGZsb3dlciAlPiUKICBncmF5c2NhbGUoKSAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpCmBgYAoKSm9pbiBkYXRhIGZyYW1lcyB3aXRoIGNvbG9yIGFuZCBncmF5c2NhbGUgdmFsdWVzOgpgYGB7cn0KZmxvd2VyX2RmIDwtIGZsb3dlcl9kZiAlPiUKICBsZWZ0X2pvaW4oZmxvd2VyX2RmX2dyYXlzY2FsZSwKICAgICAgICAgICAgYnkgPSBjKCJ4IiwgInkiKSkKYGBgCgpDb252ZXJ0IHRoZSBpbWFnZSB0byBzZiB0byB1c2Ugc2YgZnVuY3Rpb25zIHRvIGZpbmQgbmVhcmVzdCBmZWF0dXJlcyB0byBib3Jyb3cgY29sb3JzOgpgYGB7cn0KZmxvd2VyX3NmIDwtIGZsb3dlcl9kZiAlPiUKICAgIHN0X2FzX3NmKGNvb3JkcyA9IGMoIngiLCAieSIpKQoKYGBgCgpHb2xkZW4gc3BpcmFsOgpgYGB7cn0KI3BvaW50cyA8LSA1MDAKCiMgRGVmaW5pbmcgdGhlIEdvbGRlbiBBbmdsZQphbmdsZSA8LSBwaSAqICgzIC0gc3FydCg1KSkKCiN0X28gPC0gc2VxKDEsIDEwLCAxKSAKCmdzIDwtIGRhdGEuZnJhbWUodF9vID0gc2VxKDEsIDc1MCwgMC4xKSAqIGFuZ2xlKSAlPiUKICBtdXRhdGUoeF9vID0gMzAwICsgdF9vICogc2luKHRfbyksCiAgICAgICAgIHlfbyA9IDMwMCArIHRfbyAqIGNvcyh0X28pLAogICAgICAgICB4X2VuZCA9IHhfbyArIDIwICogc2luKHRfbyksCiAgICAgICAgIHlfZW5kID0geV9vICsgMjAgKiBjb3ModF9vKSkKYGBgCgpDb252ZXJ0IHRvIHNmIHRvIGJvcnJvdyB0aGUgY29sb3JzIGZyb20gdGhlIGltYWdlOgpgYGB7cn0KZ3MgPC0gZ3MgJT4lCiAgbXV0YXRlKHggPSB4X28sCiAgICAgICAgIHkgPSB5X28pICU+JQogIHN0X2FzX3NmKGNvb3JkcyA9IGMoIngiLCAieSIpKQpgYGAKCgpGaW5kIHRoZSBuZWFyZXN0IGZlYXR1cmUgaW4gdGhlIG9yaWdpbmFsIGltYWdlIHRvIGJvcnJvdyB0aGUgY29sb3JzOgpgYGB7cn0KZmxvd2VyX2NvbG9ycyA8LSBmbG93ZXJfZGZbZ3MgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RfbmVhcmVzdF9mZWF0dXJlKGZsb3dlcl9zZiksXQpgYGAKCkJpbmQgdGhlIGNvbG9ycyB0byB0aGUgcGFja2VkIGNpcmNsZXM6CmBgYHtyfQpncyA8LSBncyAlPiUKICBtdXRhdGUoY29sb3IgPSBmbG93ZXJfY29sb3JzJGNvbG9yLAogICAgICAgICB2YWx1ZSA9IGZsb3dlcl9jb2xvcnMkdmFsdWUpCmBgYAoKUGxvdDoKYGBge3J9CiMgTWFrZSBhIHNjYXR0ZXIgcGxvdCBvZiBwb2ludHMgaW4gYSBzcGlyYWwKZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YT0gZmxvd2VyX2RmLAogICAgICAgICAgICAgYWVzKHgsCiAgICAgICAgICAgICAgICAgeSwKICAgICAgICAgICAgICAgICBjb2xvciA9IHZhbHVlKSwKICAgICAgICAgICAgICNjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICBzaGFwZSA9IDE1LAogICAgICAgICAgICAgc2l6ZSA9IDYpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gTWV4QnJld2VyOjptZXguYnJld2VyKCJBdGVudGFkbyIpKSArCiAgI3NjYWxlX2NvbG9yX2Rpc3RpbGxlcihwYWxldHRlID0gIkJsdWVzIikgKwogIG5ld19zY2FsZV9jb2xvcigpICsKICBnZW9tX3NlZ21lbnQoZGF0YSA9IGdzICU+JQogICAgICAgICAgICAgICAgIGZpbHRlcih4X28gPiAxMCAmIHhfbyA8IDcxMCwKICAgICAgICAgICAgICAgICAgICAgICAgeV9vID4gMTAgJiB5X28gPCA5NTApLAogICAgICAgICAgICAgICBhZXMoeCA9IHhfbywKICAgICAgICAgICAgICAgICAgIHhlbmQgPSB4X2VuZCwKICAgICAgICAgICAgICAgICAgIHkgPSB5X28sCiAgICAgICAgICAgICAgICAgICB5ZW5kID0geV9lbmQsCiAgICAgICAgICAgICAgICAgICBzaXplID0gdF9vLAogICAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xvcikpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgc2NhbGVfY29sb3JfaWRlbnRpdHkoKSArCiAgc2NhbGVfc2l6ZShyYW5nZSA9IGMoMC4xLCAzKSkgKwogIGNvb3JkX2VxdWFsKCkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZ2dzYXZlKCJmbG93ZXItZmxvdy1maWVsZC5wbmciLAogICAgICAgaGVpZ2h0ID0gOCwKICAgICAgIHdpZHRoID0gOCwKICAgICAgIHVuaXRzID0gImluIikKYGBgCgojIyBGbG93ZXIgMiBhbmQgc3BpcmFscwoKIVtdKGZsb3dlci0yLmpwZykKClJlYWQgdGhlIGltYWdlIHVzaW5nIGBpbWFnZXI6OmxvYWQuaW1hZ2UoKWA6CmBgYHtyfQpmbG93ZXIgPC0gbG9hZC5pbWFnZSgiZmxvd2VyLTIuanBnIikKYGBgCgpDaGVjayB0aGUgc2l6ZSBvZiB0aGUgaW1hZ2U6IApgYGB7cn0KZmxvd2VyCmBgYAoKQ29udmVydCBpbWFnZSB0byBkYXRhIGZyYW1lIChzdGlsbCB3b3JraW5nIHdpdGgge2ltYWdlcn0pOgpgYGB7cn0KZmxvd2VyX2RmIDwtIGZsb3dlciAlPiUKICBhcy5kYXRhLmZyYW1lKHdpZGU9ImMiKSAlPiUgCiAgbXV0YXRlKGNvbG9yID0gcmdiKGMuMSwKICAgICAgICAgICAgICAgICAgICAgYy4yLAogICAgICAgICAgICAgICAgICAgICBjLjMpKQpgYGAKCkNvbnZlcnQgdG8gZ3JheXNjYWxlIGFuZCB0byBkYXRhIGZyYW1lOgpgYGB7cn0KZmxvd2VyX2RmX2dyYXlzY2FsZSA8LSBmbG93ZXIgJT4lCiAgZ3JheXNjYWxlKCkgJT4lIAogIGFzLmRhdGEuZnJhbWUoKQpgYGAKCkpvaW4gZGF0YSBmcmFtZXMgd2l0aCBjb2xvciBhbmQgZ3JheXNjYWxlIHZhbHVlczoKYGBge3J9CmZsb3dlcl9kZiA8LSBmbG93ZXJfZGYgJT4lCiAgbGVmdF9qb2luKGZsb3dlcl9kZl9ncmF5c2NhbGUsCiAgICAgICAgICAgIGJ5ID0gYygieCIsICJ5IikpCmBgYAoKQ29udmVydCB0aGUgaW1hZ2UgdG8gc2YgdG8gdXNlIHNmIGZ1bmN0aW9ucyB0byBmaW5kIG5lYXJlc3QgZmVhdHVyZXMgdG8gYm9ycm93IGNvbG9yczoKYGBge3J9CmZsb3dlcl9zZiA8LSBmbG93ZXJfZGYgJT4lCiAgICBzdF9hc19zZihjb29yZHMgPSBjKCJ4IiwgInkiKSkKYGBgCgpHb2xkZW4gc3BpcmFsOgpgYGB7cn0KI3BvaW50cyA8LSA1MDAKCiMgRGVmaW5pbmcgdGhlIEdvbGRlbiBBbmdsZQphbmdsZSA8LSBwaSAqICgzIC0gc3FydCg1KSkKCiN0X28gPC0gc2VxKDEsIDEwLCAxKSAKCmdzIDwtIGRhdGEuZnJhbWUodF9vID0gc2VxKDEsIDc1MCwgMC4xKSAqIGFuZ2xlKSAlPiUKICBtdXRhdGUoeF9vID0gMTYwICsgdF9vICogc2luKHRfbyksCiAgICAgICAgIHlfbyA9IDMxMCArIHRfbyAqIGNvcyh0X28pLAogICAgICAgICB4X2VuZCA9IHhfbyArIDIwICogc2luKHRfbyksCiAgICAgICAgIHlfZW5kID0geV9vICsgMjAgKiBjb3ModF9vKSkKYGBgCgpDb252ZXJ0IHRvIHNmIHRvIGJvcnJvdyB0aGUgY29sb3JzIGZyb20gdGhlIGltYWdlOgpgYGB7cn0KZ3MgPC0gZ3MgJT4lCiAgbXV0YXRlKHggPSB4X28sCiAgICAgICAgIHkgPSB5X28pICU+JQogIHN0X2FzX3NmKGNvb3JkcyA9IGMoIngiLCAieSIpKQpgYGAKCkZpbmQgdGhlIG5lYXJlc3QgZmVhdHVyZSBpbiB0aGUgb3JpZ2luYWwgaW1hZ2UgdG8gYm9ycm93IHRoZSBjb2xvcnM6CmBgYHtyfQpmbG93ZXJfY29sb3JzIDwtIGZsb3dlcl9kZltncyAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdF9uZWFyZXN0X2ZlYXR1cmUoZmxvd2VyX3NmKSxdCmBgYAoKQmluZCB0aGUgY29sb3JzIHRvIHRoZSBzcGlyYWw6CmBgYHtyfQpncyA8LSBncyAlPiUKICBtdXRhdGUoY29sb3IgPSBmbG93ZXJfY29sb3JzJGNvbG9yLAogICAgICAgICB2YWx1ZSA9IGZsb3dlcl9jb2xvcnMkdmFsdWUpCmBgYAoKUGxvdDoKYGBge3J9CiMgTWFrZSBhIHNjYXR0ZXIgcGxvdCBvZiBwb2ludHMgaW4gYSBzcGlyYWwKZ2dwbG90KCkgKwogICMgZ2VvbV9wb2ludChkYXRhPSBmbG93ZXJfZGYsCiAgIyAgICAgICAgICAgIGFlcyh4LAogICMgICAgICAgICAgICAgICAgeSwKICAjICAgICAgICAgICAgICAgIGNvbG9yID0gdmFsdWUpLAogICMgICAgICAgICAgICAjY29sb3IgPSAiYmxhY2siLAogICMgICAgICAgICAgICBzaGFwZSA9IDE1LAogICMgICAgICAgICAgICBzaXplID0gNikgKwogICMgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IE1leEJyZXdlcjo6bWV4LmJyZXdlcigiQXRlbnRhZG8iKSkgKwogICMgc2NhbGVfY29sb3JfZGlzdGlsbGVyKHBhbGV0dGUgPSAiQmx1ZXMiKSArCiAgIyBuZXdfc2NhbGVfY29sb3IoKSArCiAgZ2VvbV9zZWdtZW50KGRhdGEgPSBncyAlPiUKICAgICAgICAgICAgICAgICBmaWx0ZXIoeF9vID4gMTAgJiB4X28gPCA3MTAsCiAgICAgICAgICAgICAgICAgICAgICAgIHlfbyA+IDEwICYgeV9vIDwgOTUwKSwKICAgICAgICAgICAgICAgYWVzKHggPSB4X28sCiAgICAgICAgICAgICAgICAgICB4ZW5kID0geF9lbmQsCiAgICAgICAgICAgICAgICAgICB5ID0geV9vLAogICAgICAgICAgICAgICAgICAgeWVuZCA9IHlfZW5kLAogICAgICAgICAgICAgICAgICAgc2l6ZSA9IHRfbywKICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY29sb3IpKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKwogIHNjYWxlX2NvbG9yX2lkZW50aXR5KCkgKwogIHNjYWxlX3NpemUocmFuZ2UgPSBjKDAuMSwgMykpICsKICBjb29yZF9lcXVhbCgpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmdnc2F2ZSgiZmxvd2VyLTItZmxvdy1maWVsZC5wbmciLAogICAgICAgaGVpZ2h0ID0gOCwKICAgICAgIHdpZHRoID0gOCwKICAgICAgIHVuaXRzID0gImluIikKYGBgCgojIyBLbm90cyAobm9kYWwgY3VydmVzKTogc2VlIGh0dHBzOi8vbWF0aGN1cnZlLmNvbS9jb3VyYmVzMmQuZ2Ivbm9ldWQvbm9ldWQuc2h0bWwgCgpQb2xhciBlcXVhdGlvbjoKJCQKXHJobyA9IGEgXHRhbihuXHRoZXRhKQokJApvcjoKJCQKXHJobyA9IGEgXGNvdChuXHRoZXRhKQokJAp3aXRoICRuPjAkLiBFYWNoIGN1cnZlIGlzIG9idGFpbmVkIGZvcjoKJCQKLVxmcmFje1xwaX17Mm59IDwgXHRoZXRhIDwgXGZyYWN7XHBpfXsybn0KJCQKCkNyZWF0ZSBhIGRhdGEgZnJhbWUgdG8gY2FsY3VsYXRlIHRoZSB2YWx1ZXMgb2YgdGhlIGtub3QgZnVuY3Rpb24gd2l0aCBwYXJhbWV0ZXJzICRhJCBhbmQgJG4kLiBJZiAkbiQgaXMgYSByYXRpb25hbCBudW1iZXIgJHAvcSQsIHRoZSBudW1iZXIgb2YgYnJhbmNoZXMgaXMgJDJwJCBpZiAkcSQgaXMgb2RkLCBhbmQgJHAkIGlmICRxJCBpcyBldmVuLiBFYWNoIHJvdGF0aW9uIG9mIGEgYnJhbmNoIGlzIGJ5IGFuIGFuZ2xlIG9mICRccGkvbiQ6CmBgYHtyfQojIFNjYWxlIGZhY3RvcgphIDwtIDEKI0V4dGVudCBvZiB2YWx1ZXM6IGxhcmdlciBleHQgbWVhbnMgdGhhdCBmZXdlciBhbmdsZXMgdGhldGEgd2lsbCBiZSB1c2VkIGluIHRoZSBjYWxjdWxhdGlvbi4gSWYgZXh0ID09IDEgdGhlbiB0aGUgd2hvbGUgZG9tYWluIC1waS8oMm4pIHRvIHBpLygybikgaXMgdXNlZApleHQgPC0gMTAgIyBNdXN0IGJlIGdyZWF0ZXIgdGhhbiAxCnAgPC0gNgpxIDwtIDUKbiA8LSBwL3EKIyBOdW1iZXIgb2YgYnJhbmNoZXMKbmIgPC0gaWZlbHNlKHEgJSUgMiA9PSAxLCAyICogcCwgcCkKCiMgSW5pdGlhbGl6ZSBkYXRhIGZyYW1lCmRmIDwtIGRhdGEuZnJhbWUodCA9IHNlcSgtcGkvKGV4dCAqIDIgKiBuKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBwaS8oZXh0ICogMiAqIG4pLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aC5vdXQgPSAxODApKSAlPiUKICBzbGljZSgzOjE3OCkKCmRmIDwtIGRmICU+JQogICMgUm90YXRpb24gb2YgYnJhbmNoZXMgaXMgYmV0d2VlbiAwIGFuZCAyICogcGkgKHdoaWNoIHJlcGxpY2F0ZXMgemVybyk7IHRoZSBzdGVwIGluY3JlbWVudHMgYXJlIHRoZSAyICogcGkgZGl2aWRlZCBieSBudW1iZXIgb2YgYnJhbmNoZXMKICBjYmluZChrID0gcmVwKHNlcSgwLCAyICogcGkgKiAoMSAtIDEvbmIpLCBieSA9IDIgKiBwaS9uYiksIGVhY2ggPSBucm93KGRmKSkpICU+JQogICMgQ2FsY3VsYXRlIHBvbGFyIGNvb3JkaW5hdGVzIGFuZCB0aGVuIGNvbnZlcnQgdG8gY2FydGVzaWFuIGNvb3JkaW5hdGVzCiAgbXV0YXRlKHIgPSBhICogdGFuKG4gKiAodCArIGspKSwKICAgICAgICAgeCA9IHIgKiBjb3ModCArIGspLAogICAgICAgICB5ID0gciAqIHNpbih0ICsgaykpICMlPiUKICAjICMgUm90YXRpb24KICAjIG11dGF0ZSh4ID0geCAqIGNvcyhrKSAtIHkgKiBzaW4oayksCiAgIyAgICAgICAgeSA9IHggKiBzaW4oaykgKyB5ICogY29zKGspKQogIApgYGAKClBsb3Q6CmBgYHtyfQpnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZGYsCiAgICAgICAgICAgICBhZXMoeCwKICAgICAgICAgICAgICAgICB5LAogICAgICAgICAgICAgICAgIGNvbG9yID0gZmFjdG9yKGspKSkgKyAKICBjb29yZF9lcXVhbCgpCmBgYAoKCiMjIERvcGxlciBzcGlyYWw6IHNlZSBodHRwczovL21hdGhjdXJ2ZS5jb20vY291cmJlczJkLmdiL2RvcHBsZXIvZG9wcGxlci5odG0KClBhcmFtZXRyaWMgZXF1YXRpb25zOgokJAp4ID0gYSh0XGNvcyh0KSArIGt0KQokJAphbmQ6CiQkCnkgPSBhdFxzaW4odCkKJCQKCkNyZWF0ZSBhIGRhdGEgZnJhbWUgdG8gY2FsY3VsYXRlIHRoZSB2YWx1ZXMgb2YgdGhlIHNwaXJhbCB3aXRoIHBhcmFtZXRlcnMgJGEkIGFuZCAkayQ6CmBgYHtyfQojIFNjYWxlIGZhY3RvcgphIDwtIDMKayA8LSAwLjUKCiMgSW5pdGlhbGl6ZSBkYXRhIGZyYW1lCmRmIDwtIGRhdGEuZnJhbWUodCA9IHNlcSgwLCAKICAgICAgICAgICAgICAgICAgICAgICAgIDE1MCwgCiAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGgub3V0ID0gMzAwKSkgJT4lCiAgIyBDYWxjdWxhdGUgcG9sYXIgY29vcmRpbmF0ZXMgYW5kIHRoZW4gY29udmVydCB0byBjYXJ0ZXNpYW4gY29vcmRpbmF0ZXMKICBtdXRhdGUoeCA9IGEgKiAodCAqIGNvcyh0KSArIGsgKiB0KSwKICAgICAgICAgeSA9IGEgKiB0ICogc2luKHQpLAogICAgICAgICB4X2VuZCA9IHggLSAyMCAqIGNvcyh0KSwKICAgICAgICAgeV9lbmQgPSB5ICsgMjAgKiBzaW4odCkpCmBgYAoKUGxvdDoKYGBge3J9CmdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkZiwKICAgICAgICAgICAgIGFlcyh4LAogICAgICAgICAgICAgICAgIHksCiAgICAgICAgICAgICAgICAgY29sb3IgPSB0KSkgKyAKICBnZW9tX3NlZ21lbnQoZGF0YSA9IGRmLAogICAgICAgICAgICAgYWVzKHgsCiAgICAgICAgICAgICAgICAgeSwKICAgICAgICAgICAgICAgICB4ZW5kID0geF9lbmQsCiAgICAgICAgICAgICAgICAgeWVuZCA9IHlfZW5kKSkgKwogIGNvb3JkX2VxdWFsKCkKYGBgCgojIyBGbG93ZXJzIGFuZCBzcGlyYWxzCgohW10oZmxvd2Vycy10aXRpLmpwZykKClJlYWQgdGhlIGltYWdlIHVzaW5nIGBpbWFnZXI6OmxvYWQuaW1hZ2UoKWA6CmBgYHtyfQpmbG93ZXIgPC0gbG9hZC5pbWFnZSgiZmxvd2Vycy10aXRpLmpwZyIpCmBgYAoKQ2hlY2sgdGhlIHNpemUgb2YgdGhlIGltYWdlOiAKYGBge3J9CmZsb3dlcgpgYGAKCkNvbnZlcnQgaW1hZ2UgdG8gZGF0YSBmcmFtZSAoc3RpbGwgd29ya2luZyB3aXRoIHtpbWFnZXJ9KToKYGBge3J9CmZsb3dlcl9kZiA8LSBmbG93ZXIgJT4lCiAgYXMuZGF0YS5mcmFtZSh3aWRlPSJjIikgJT4lIAogIG11dGF0ZShjb2xvciA9IHJnYihjLjEsCiAgICAgICAgICAgICAgICAgICAgIGMuMiwKICAgICAgICAgICAgICAgICAgICAgYy4zKSkKYGBgCgpDb252ZXJ0IHRvIGdyYXlzY2FsZSBhbmQgdG8gZGF0YSBmcmFtZToKYGBge3J9CmZsb3dlcl9kZl9ncmF5c2NhbGUgPC0gZmxvd2VyICU+JQogIGdyYXlzY2FsZSgpICU+JSAKICBhcy5kYXRhLmZyYW1lKCkKYGBgCgpKb2luIGRhdGEgZnJhbWVzIHdpdGggY29sb3IgYW5kIGdyYXlzY2FsZSB2YWx1ZXM6CmBgYHtyfQpmbG93ZXJfZGYgPC0gZmxvd2VyX2RmICU+JQogIGxlZnRfam9pbihmbG93ZXJfZGZfZ3JheXNjYWxlLAogICAgICAgICAgICBieSA9IGMoIngiLCAieSIpKQpgYGAKCkNvbnZlcnQgdGhlIGltYWdlIHRvIHNmIHRvIHVzZSBzZiBmdW5jdGlvbnMgdG8gZmluZCBuZWFyZXN0IGZlYXR1cmVzIHRvIGJvcnJvdyBjb2xvcnM6CmBgYHtyfQpmbG93ZXJfc2YgPC0gZmxvd2VyX2RmICU+JQogICAgc3RfYXNfc2YoY29vcmRzID0gYygieCIsICJ5IikpCmBgYAoKQ3JlYXRlIGEgZGF0YSBmcmFtZSB0byBjYWxjdWxhdGUgdGhlIHZhbHVlcyBvZiB0aGUgc3BpcmFsIHdpdGggcGFyYW1ldGVycyAkYSQgYW5kICRrJDoKYGBge3J9CiMgU2NhbGUgZmFjdG9yCmEgPC0gMC4yNQprIDwtIDAuMQoKIyBJbml0aWFsaXplIGRhdGEgZnJhbWUKZHMgPC0gZGF0YS5mcmFtZSh0ID0gc2VxKDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgMzUwMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGgub3V0ID0gODAwMCkpICU+JQogICMgQ2FsY3VsYXRlIHBvbGFyIGNvb3JkaW5hdGVzIGFuZCB0aGVuIGNvbnZlcnQgdG8gY2FydGVzaWFuIGNvb3JkaW5hdGVzCiAgbXV0YXRlKHhfbyA9IDIyMCArIGEgKiAodCAqIGNvcyh0KSArIGsgKiB0KSwKICAgICAgICAgeV9vID0gNDYwICsgYSAqIHQgKiBzaW4odCksCiAgICAgICAgIHhfZW5kID0geF9vIC0gdC8yMDAgKiBjb3ModCksCiAgICAgICAgIHlfZW5kID0geV9vICsgdC8yMDAgKiBzaW4odCkpCmBgYAoKQ29udmVydCB0byBzZiB0byBib3Jyb3cgdGhlIGNvbG9ycyBmcm9tIHRoZSBpbWFnZToKYGBge3J9CmRzIDwtIGRzICU+JQogIG11dGF0ZSh4ID0geF9vLAogICAgICAgICB5ID0geV9vKSAlPiUKICBzdF9hc19zZihjb29yZHMgPSBjKCJ4IiwgInkiKSkKYGBgCgpGaW5kIHRoZSBuZWFyZXN0IGZlYXR1cmUgaW4gdGhlIG9yaWdpbmFsIGltYWdlIHRvIGJvcnJvdyB0aGUgY29sb3JzOgpgYGB7cn0KZmxvd2VyX2NvbG9ycyA8LSBmbG93ZXJfZGZbZHMgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RfbmVhcmVzdF9mZWF0dXJlKGZsb3dlcl9zZiksXQpgYGAKCkJpbmQgdGhlIGNvbG9ycyB0byB0aGUgc3BpcmFsOgpgYGB7cn0KZHMgPC0gZHMgJT4lCiAgbXV0YXRlKGNvbG9yID0gZmxvd2VyX2NvbG9ycyRjb2xvciwKICAgICAgICAgdmFsdWUgPSBmbG93ZXJfY29sb3JzJHZhbHVlKQpgYGAKClBsb3Q6CmBgYHtyfQojIE1ha2UgYSBzY2F0dGVyIHBsb3Qgb2YgcG9pbnRzIGluIGEgc3BpcmFsCmdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGE9IGZsb3dlcl9kZiwKICAgICAgICAgICAgIGFlcyh4LAogICAgICAgICAgICAgICAgIHksCiAgICAgICAgICAgICAgICAgY29sb3IgPSB2YWx1ZSksCiAgICAgICAgICAgICAjY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgc2hhcGUgPSAxNSwKICAgICAgICAgICAgIHNpemUgPSA2KSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IE1leEJyZXdlcjo6bWV4LmJyZXdlcigiQXRlbnRhZG8iKSkgKwogICNzY2FsZV9jb2xvcl9kaXN0aWxsZXIocGFsZXR0ZSA9ICJCbHVlcyIpICsKICBuZXdfc2NhbGVfY29sb3IoKSArCiAgZ2VvbV9zZWdtZW50KGRhdGEgPSBkcyAlPiUKICAgICAgICAgICAgICAgICBmaWx0ZXIoeF9vID4gLTEwICYgeF9vIDwgOTcwLAogICAgICAgICAgICAgICAgICAgICAgICB5X28gPiAtMTAgJiB5X28gPCA2NTApLAogICAgICAgICAgICAgICBhZXMoeCA9IHhfbywKICAgICAgICAgICAgICAgICAgIHhlbmQgPSB4X2VuZCwKICAgICAgICAgICAgICAgICAgIHkgPSB5X28sCiAgICAgICAgICAgICAgICAgICB5ZW5kID0geV9lbmQsCiAgICAgICAgICAgICAgICAgICBzaXplID0gdCwKICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY29sb3IpKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKwogIHNjYWxlX2NvbG9yX2lkZW50aXR5KCkgKwogIHNjYWxlX3NpemUocmFuZ2UgPSBjKDEsIDQpKSArCiAgY29vcmRfZXF1YWwoKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpnZ3NhdmUoImZsb3dlci10aXRpLWZsb3ctZmllbGQtYXRlbnRhZG8ucG5nIiwKICAgICAgIGhlaWdodCA9IDgsCiAgICAgICB3aWR0aCA9IDgsCiAgICAgICB1bml0cyA9ICJpbiIpCmBgYAoKVHJ5IHRoaXMgKHNlZTogaHR0cHM6Ly93d3cuZmFjZWJvb2suY29tL21oZXJuYW5kZXphcnJlc2UvcG9zdHMvMTAxNTg2NTI2MDUwMzI4MjUpOgoKIVtdKG90dGF3YS5qcGcpCgoKQW5kIHRoaXMgYnkgTWlrZSBLdWt1Y3NrYToKCiFbXShtay1zdW5yaXNlLmpwZykK